<?php
#
# This script is aimed at restoring postgis data
# from a dumpfile produced by pg_dump -Fc
#
# Basically it will restore all but things created by
# the given postgis.sql.
# Before restoring, it will create and postgis-enable
# the target db.
#
# A particular attention must be given to the spatial_ref_sys
# and geometry_columns tables which are created and populated
# from the dump, not the postgis.sql file. When the new installation
# is agains pgsql7.5+ and dump from pre7.5 this script should probably
# drop statistic fields from that table.... currently not done.
# Also, when upgrading to pgsq8.1+ (from <8.1) the oid column of
# geometry_columns  will be dropped, while it is needed for
# postgis opearations.
#
# Issues:
#	o Some obsoleted functions would not be present in the
#	  postgis.sql, but will be found in the dump. Currently
#	  some are skipped, but some depend on the pg version
#	  so will issue an ERROR due to unavailability of
#	  corresponding C function in postgis lib.
#	 
# 	o This script could do less then it does, to allow users
#	  to further modify edited dump before feeding it to the
#	  restoring side.
#
# Tested on:
#
#	pg_dump-734/pg734 => pg_restore-743/pg743
#	pg_dump-743/pg734 => pg_restore-743/pg743
#	pg_dump-743/pg743 => pg_restore-743/pg743
#	pg_dump-734/pg734 => pg_restore-800/pg800
#	pg_dump-743/pg734 => pg_restore-800/pg800
#	pg_dump-743/pg743 => pg_restore-800/pg800
#	pg_dump-800/pg800 => pg_restore-800/pg800
#
if(sizeof($argv) < 3) {
	exit("Usage: postgis_restore.php <postgis.sql> <db> <dump> [<createdb_options>]\nRestore a custom dump (pg_dump -Fc) of a postgis enabled database.\n");
}

$DEBUG = 1;

$aggs = array();
$casts = array();
$funcs = array();
$types = array();
$opclass = array();
$ops = array();

# This are old postgis functions which might
# still be in a dump
$obsoleted_function = array(
	'linefromtext',
	'linestringfromtext',
	'mlinefromtext',
	'multilinestringfromtext',
	'mpolyfromtext',
	'multipolygonfromtext',
	'polyfromtext',
	'polygonfromtext',
	'pointfromtext',
	'mpointfromtext',
	'multipointfromtext',
	'geomcollfromtext',
	'geometryfromtext',
	'geomfromtext',
	'pointfromwkb(geometry, integer)',
	'pointfromwkb(geometry)',
	'linefromwkb(geometry, integer)',
	'linefromwkb(geometry)',
	'linestringfromwkb(geometry, integer)',
	'linestringfromwkb(geometry)',
	'polyfromwkb(geometry, integer)',
	'polyfromwkb(geometry)',
	'polygonfromwkb(geometry, integer)',
	'polygonfromwkb(geometry)',
	'mpointfromwkb(geometry, integer)',
	'mpointfromwkb(geometry)',
	'multipointfromwkb(geometry, integer)',
	'multipointfromwkb(geometry)',
	'multilinefromwkb(geometry, integer)',
	'multilinefromwkb(geometry)',
	'mlinefromwkb(geometry, integer)',
	'mlinefromwkb(geometry)',
	'mpolyfromwkb(geometry, integer)',
	'mpolyfromwkb(geometry)',
	'multipolyfromwkb(geometry, integer)',
	'multipolyfromwkb(geometry)',
	'geomcollfromwkb(geometry, integer)',
	'geomcollfromwkb(geometry)',
	'wkb_in',
	'wkb_out',
	'wkb_recv',
	'wkb_send',
	'postgisgistcostestimate',
	'ggeometry_compress',
	'ggeometry_picksplit',
	'gbox_picksplit',
	'ggeometry_union',
	'gbox_union',
	'ggeometry_same',
	'gbox_same',
	'rtree_decompress',
	'ggeometry_penalty',
	'gbox_penalty',
	'geometry_union(geometry, geometry)',
	'geometry_inter(geometry, geometry)',
	'geometry_size',
	'ggeometry_consistent',
	'create_histogram2d(box3d, integer)',
	'estimate_histogram2d(histogram2d, box)',
	'xmin(box2d)',
	'ymin(box2d)',
	'xmax(box2d)',
	'ymax(box2d)',
	'optimistic_overlap',
	'unite_finalfunc',
	'numb_sub_objs(geometry)',
	'truly_inside(geometry, geometry)',
);

# This are old postgis operators which might
# still be in a dump
$obsoleted_ops = array(
	'>>,box2d,box2d',
	'<<,box2d,box2d',
	'&>,box2d,box2d',
	'&<,box2d,box2d',
	'&&,box2d,box2d',
	'~=,box2d,box2d',
	'~,box2d,box2d',
	'@,box2d,box2d',
);

$postgissql = $argv[1];
$dbname = $argv[2];
$dump = $argv[3];
$createdb_opt = '';
$dumplist = $dump . ".list";
$dumpascii = $dump . ".ascii";

if ($argv) $createdb_opt = implode(' ', $argv);

print("postgis.sql is $postgissql\n");
print("dbname is $dbname\n");
print("dumpfile is $dump\n");
print("database creation options: $createdb_opt\n");


#
# Canonicalize type names (they change between dump versions).
# Here we also strip schema qualification
#
function canonicalize_typename($arg) {

	# Lower case
	$arg = strtolower($arg);
  
	# Trim whitespaces
	$arg = trim($arg);
  
	# Strip schema qualification
	#$arg = ereg_replace("^public.", '', $arg);
	$arg = ereg_replace("^.*\.", '', $arg);
  
	# Handle type name changes
	if ($arg == 'opaque') {
		$arg = 'internal';
	} elseif ($arg == 'boolean') {
		$arg = 'bool';
	} elseif ($arg == 'oldgeometry') {
		$arg = 'geometry';
	}

	# Timestamp with or without time zone
  if (ereg("timestamp .* time zone", $arg)) {
		$arg = 'timestamp';
	}

	return $arg;
}

#
# Scan postgis.sql
#
print("Scanning $postgissql\n"); 
$fp = @fopen($postgissql, 'r');
if ($fp===false) exit("Couldn't open file: $postgissql\n");
while (($line = fgets($fp)) !== false) {
  #print("LINE: $line");
  
  if (preg_match("/^[ |\t]*--/", $line)) continue;
  
  if (preg_match("/^[ |\t]*create (or replace)? function ([^ ]*) *\((.*)\)/i", $line, $regs)) {
    $name = strtolower($regs[2]);
    $args = split(",", $regs[3]);
		$geomfound = 0;
		for ($i=0; $i < sizeof($args); $i++)
		{
			$arg = strtolower($args[$i]);
//			print "ARG1: [$arg]\n";
			$arg = trim($arg);
//			print "ARG2: [$arg]\n";
			if (preg_match("/^int[48]?$/", $arg)) {
				$args[$i] = 'integer';
				next;
			}
			if ($arg == 'float4') {
				$args[$i] = 'real';
				next;
			}
			if ($arg == 'float8') {
				$args[$i] = 'double precision';
				next;
			}
			if ($arg == 'varchar' ) {
				$args[$i] = 'character varying';
				next;
			}
			if ($arg == 'boolean' ) {
				$args[$i] = 'bool';
				next;
			}
			if ($arg == 'opaque' ) {
				$args[$i] = 'internal';
				next;
			}
			$args[$i] = $arg;
			if ($arg == 'oldgeometry') $geomfound++;
		}
		$id = $name . "(" . implode(", ", $args) . ")";
  	$funcs{$id} = 1;
  	if ($DEBUG) print "SQLFUNC: $id\n";			
  	if ($geomfound) {
  		for ($i=0; $i < sizeof($args); $i++) {
  			$arg = $args[$i];
  			if ($arg == 'oldgeometry') $arg = 'geometry';
  			$args[$i] = $arg;
  		}
  		$id = $name . "(" . implode(", ", $args) . ")";
  		$funcs{$id} = 1;
  		if ($DEBUG) print "SQLFUNC2: $id\n";
  	}
  	next;
  }
	if (preg_match("/^create type +([^ ]+)/i", $line, $regs)) {
		$type = $regs[1];
		$types[$type] = 1;
		if ($DEBUG) print "SQLTYPE $type\n";
		if ($type eq 'oldgeometry' ) {
			$type = 'geometry';
			$types[$type] = 1;
			if ($DEBUG) print "SQLTYPE $type\n";
		}
		next;
	}
  if (preg_match("/^create aggregate *([^ ]*) *\(/i", $line, $regs)) {
    $name = strtolower($regs[1]);
    $name = preg_replace("s/^public./","",$name);
    unset($type);
    while (($subline = fgets($fp)) !== false) {
      if (preg_match("/basetype .* ([^, ]*)/", $subline, $regssub)) {
				$type = $regssub[1];
				break;
			}
			if (preg_match("/;[\t ]*$/", $subline)) break;
		}
		if (!$type) {
			print "Could not find base type for aggregate $name\n";
			print "($line)\n";
			exit;
		}
		$id = $name.'('.$type.')';
		print "SQLAGG $id\n" if $DEBUG;
		$aggs[$id] = 1;
		if ($type == 'oldgeometry') {
			$type = 'geometry';
			$id = $name.'('.$type.')';
			$aggs[$id] = 1;
			if ($DEBUG) print "SQLAGG $id\n";
		}
		next;
  }
}
fclose($fp);
#exit;


#
# Scan dump list
#
print("Scanning $dump list\n"); 



?>